package troisdimension.client;

import java.util.ArrayList;
import java.util.List;

import org.apache.tools.ant.util.StringUtils;

import com.google.gwt.canvas.client.Canvas;
import com.google.gwt.canvas.dom.client.Context2d;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.dom.client.Element;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.MouseMoveEvent;
import com.google.gwt.event.dom.client.MouseMoveHandler;
import com.google.gwt.event.dom.client.MouseWheelEvent;
import com.google.gwt.event.dom.client.MouseWheelHandler;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.SplitLayoutPanel;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class troisdimension implements EntryPoint {

	Canvas canvas;
	Context2d context;
	static final int canvasHeight = 600;
	static final int canvasWidth = 1000;
	ArrayList<Point> listePoint = new ArrayList<Point>();
	ConteneurForme forme = new ConteneurForme();
	String infoPoint = "";
	PointCentral ptC = null;

	public String getInfoPoint() {
		return infoPoint;
	}

	public void setInfoPoint(String infoPoint) {
		this.infoPoint = infoPoint;
	}

	private native void menu(troisdimension t3d)
	/*-{
		
	   var requestAnimFrame = (function(){
      return  $wnd.requestAnimationFrame       || 
              $wnd.webkitRequestAnimationFrame || 
              $wnd.mozRequestAnimationFrame    || 
              $wnd.oRequestAnimationFrame      || 
              $wnd.msRequestAnimationFrame     || 
              function( callback ){
                $wnd.setTimeout(callback, 1000/60);
              };
    })();
    
			 
		var FizzyText = function() {
		  this.displayOutline = false;
		  this.SelectionLigne = '0';
	      this.Point1 ='0';
	      this.Point2 ='0';	
		  this.epaisseurLigne = 1;
		  this.couleurLigne = "#ffae23"; 
		  
		  	
		  // -> Camera
		  this.camera= function() {
		  };	 	  
		  this.selectionCamera = '0';
		  this.xCentral = '0';
		  this.yCentral = '0';
		  this.zCentral = '0';
		  this.xAngle = 0;
		  this.yAngle = 0;
		  this.zAngle = 0;
		  this.profondeur = '500';
		  this.focal = '1000';
		  
		  // -> Point
		  this.point= function() {
		  };
		  this.SelectionPoint = '0';
		  this.pointx = '0';
		  this.pointy = '0';
		  this.pointz = '10';
		  this.rayonPoint = 5;
		  this.couleurPoint = "#ffae23"; 	  
		  this.AjouterPoint = function() {

		  	 t3d.@troisdimension.client.troisdimension::ajouterPoint(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)
		  	 ('cercle',this.xCentral,this.yCentral,this.zCentral, this.xAngle.toString(),this.yAngle.toString(),this.zAngle.toString(), this.pointx,this.pointy,this.pointz,this.rayonPoint.toString(),this.couleurPoint ,this.focal);
	
		  };
		  this.SupprimerPoint= function() {
		  };
		  
		  // -> Ligne
		  this.ligne= function() {
		  };	  
		  this.AjouterLigne= function() {
		  	  	 t3d.@troisdimension.client.troisdimension::ajouterLigne(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)
		  	 ('Ligne',this.xCentral,this.yCentral,this.zCentral, this.xAngle.toString(),this.yAngle.toString(),this.zAngle.toString(), this.Point1,this.Point2,this.epaisseurLigne.toString(),this.couleurLigne ,this.focal);
	
		  	
		  };
		  this.SupprimerLigne= function() {
		  };
		  
		  // -> Structure
		  this.Structure = function() {
		  };
		  this.SelectionPoint = '0';
 		  this.SelectionLigne = '0';
 		  this.AjouterStructure  = function() {
 		  	         t3d.@troisdimension.client.troisdimension::ajouterStructure(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)
 	    	 ('structure',this.xCentral,this.yCentral,this.zCentral, this.xAngle.toString(),this.yAngle.toString(),this.zAngle.toString(), this.SelectionLigne,this.epaisseurLigne.toString(),this.couleurLigne ,this.focal);
	  	
		  };
 		  this.SupprimerStructure = function() {
		  };
		  this.SelectionStructure  = function() {
		  };
		  

		  this.deplacerAuto = function() {
 	         t3d.@troisdimension.client.troisdimension::deplacerForme(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)
 	         (this.selectionPoint,this.xCentral,this.yCentral,this.zCentral,this.xAngle.toString(),this.yAngle.toString(),this.zAngle.toString(),this.focal);
		  };
		  
		  this.deplacerManu = function() {
 			t3d.@troisdimension.client.troisdimension::deplacerFormeAll(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)
 	         (this.xCentral,this.yCentral,this.zCentral,this.xAngle.toString(),this.yAngle.toString(),this.zAngle.toString(),this.focal); 		  };
		  
		  this.toutdeplacer = function() {
		  	update = move;
		  	update(); 	 
		  };
		  
		  this.arret = function() {
		  			  update= null;
		   };

		};
		 var text = new FizzyText();

	     var move = function() {
			  requestAnimFrame(update);
			  var d = new Date();
			  text.yAngle = 180 + Math.cos(d.getTime()/1000) * 180;
			 		  	        t3d.@troisdimension.client.troisdimension::deplacerFormeAll(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)
 	         (text.xCentral,text.yCentral,text.zCentral,text.xAngle.toString(),text.yAngle.toString(),text.zAngle.toString(),text.focal); 
		  }; 
		 var update = move;

    

 		 var geo = new  $wnd.dat.GUI({ autoPlace: false , width : 280}); 		  
    	 
    	  var Camera = new $wnd.dat.GUI({ autoPlace: false, width : 280 });    	 
    	  var PointCentral = Camera.addFolder('Camera');    	  	  
		  PointCentral.add(text, 'selectionCamera');
		  PointCentral.add(text, 'xCentral');
		  PointCentral.add(text, 'yCentral');
		  PointCentral.add(text, 'zCentral');
		  PointCentral.add(text, 'focal');		  
		  PointCentral.add(text, 'profondeur');
		  PointCentral.add(text, 'deplacerAuto');
		  PointCentral.add(text, 'deplacerManu');
		  PointCentral.add(text, 'toutdeplacer');
		  PointCentral.add(text, 'arret');

 		 var Point = Camera.addFolder('Point'); 		  
		 Point.add(text, 'SelectionPoint');
		 Point.add(text, 'pointx');
		 Point.add(text, 'pointy');
		 Point.add(text, 'pointz');
		 Point.add(text, 'rayonPoint',0, 500);
		 Point.addColor(text, 'couleurPoint');		  
		 Point.add(text, 'AjouterPoint');
		 Point.add(text, 'SupprimerPoint'); 
		
		 var Ligne = Camera.addFolder('Ligne');  		 
		 Ligne.add(text, 'SelectionLigne');
         Ligne.add(text, 'Point1');
         Ligne.add(text, 'Point2');
		 Ligne.add(text, 'epaisseurLigne',0, 500);
		 Ligne.addColor(text, 'couleurLigne');		  
		 Ligne.add(text, 'AjouterLigne');
		 Ligne.add(text, 'SupprimerLigne');	
			
		 var Structure = Camera.addFolder('Structure');  
 		 Structure.add(text, 'Structure');
 		 Structure.add(text, 'SelectionPoint');
 		 Structure.add(text, 'SelectionLigne');
 		 Structure.add(text, 'SelectionStructure');
 		 Structure.add(text, 'AjouterStructure');
 		 Structure.add(text, 'SupprimerStructure');



          var Rotation = new $wnd.dat.GUI({ autoPlace: false, width : 500 }); 
          var r = Rotation.addFolder('Rotation');    	  	  
		  r.add(text, 'xAngle',0, 360);
		  r.add(text, 'yAngle',0, 360).listen();
		  r.add(text, 'zAngle',0, 360);

	      var divCamera = $doc.getElementById('divCamera');
	      divCamera.appendChild(Camera.domElement);
	      divCamera.appendChild(geo.domElement);
	      
	      var divRotation = $doc.getElementById('divRotation');
	      divRotation.appendChild(Rotation.domElement);

          Point.open();
          Ligne.close();
          Structure.close();
          PointCentral.close();
          r.open();

	 }-*/;

	public void onModuleLoad() {	
		initCanvas();
		troisdimension m = new troisdimension();
		m.menu(this);
	}

	private void initCanvas() {
		canvas = Canvas.createIfSupported();

		if (canvas == null) {
			RootPanel
					.get()
					.add(new Label(
							"Sorry, your browser doesn't support the HTML5 Canvas element"));
			return;
		}

		// canvas.setStyleName("mainCanvas");
		canvas.setWidth(canvasWidth + "px");
		canvas.setCoordinateSpaceWidth(canvasWidth);

		canvas.setHeight(canvasHeight + "px");
		canvas.setCoordinateSpaceHeight(canvasHeight);

		//HTML centre = new HTML("<div id='canvas'></div><h2 id='x'></h2><h6 id='x1'></h6>");

		HTML divCamera = new HTML("<div id='divCamera'></div><h5 id='positionRelatif'></h5><h5 id='positionAzero'></h5>");
		HTML divGeo = new HTML("<div id='divGeo'></div>");
		HTML divRotation = new HTML("<div id='divRotation' class='tourner'></div>");		
		SplitLayoutPanel p = new SplitLayoutPanel();	
		p.setPixelSize(2000, 800);
		p.addWest(divCamera, 280);
		p.addEast(divRotation, 800);
		p.add(canvas);
		
		RootPanel.get().add(p);
	
		context = canvas.getContext2d();

		canvas.addMouseMoveHandler(new MouseMoveHandler() {
			@Override
			public void onMouseMove(MouseMoveEvent event) {
				if (ptC != null) {
					Element positionRelatif = getElementById("positionRelatif");
					Element positionAzero = getElementById("positionAzero");
					Point p = transformation.getPosition3d(500 - event.getX(),
							300-event.getY(), transformation.z, ptC);										
					positionRelatif.setInnerHTML("positionRelatif: X-"  + p.getXA() + " -Y- " + p.getYA() + " -Z- "
							+ p.getZA());
					positionAzero.setInnerHTML("positionAzero : "  + p.getxAngle0() + "  " + p.getyAngle0() + " "
							+ p.getzAngle0());  
				}		
			}
		});
		
		canvas.addMouseWheelHandler(new MouseWheelHandler() {
			   public void onMouseWheel(MouseWheelEvent event) {	
			      if(event.isNorth()) {
			    	  transformation.z = transformation.z + 1 ;
			      } else {
			    	  transformation.z = transformation.z - 1 ;
			      }
			   }
			});
		
		canvas.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				Point p = transformation.getPosition3d(500- event.getX(),
						300 - event.getY(), transformation.z, ptC);
				ajouterPoint("cercle","2" ,"#ffae23", p.getXA(), p.getYA(),p.getZA());
		
			}
		});

		construireGrille();

		// Get a random color and alpha transparency
		/*
		 * int rndRedColor = Random.nextInt(255); int rndGreenColor =
		 * Random.nextInt(255); int rndBlueColor = Random.nextInt(255); double
		 * rndAlpha = Random.nextDouble();
		 * 
		 * CssColor randomColor = CssColor.make("rgba(" + rndRedColor + ", " +
		 * rndGreenColor + "," + rndBlueColor + ", " + rndAlpha + ")");
		 * 
		 * context.setFillStyle(randomColor); context.fillRect(0, 0, 1000, 600);
		 * context.fill();
		 * 
		 * CssColor forme = CssColor.make("rgba(100,50,10,5)");
		 * 
		 * Point p1 = new Point(10, 50); Point p2 = new Point(300, 50); Point p3
		 * = new Point(400, 300); Point p4 = new Point(10, 100);
		 * 
		 * context.setFillStyle(forme); context.setLineWidth(1);
		 * context.beginPath(); context.moveTo(p1.getX(), p1.getY());
		 * context.lineTo(p2.getX(), p2.getY());
		 * context.bezierCurveTo(p3.getX(), p3.getY(), p4.getX(), p4.getY(),
		 * p1.getX(), p1.getY()); context.stroke(); context.closePath();
		 * context.save();
		 * 
		 * 
		 * listePoint = listePositionDansLigne(listePoint, p1, p2); listePoint =
		 * listePositionDansLigne(listePoint, p2,p3,p4,p1);
		 * 
		 * final Timer timer = new Timer() {
		 * 
		 * @Override public void run() { dessine(); } };
		 * timer.scheduleRepeating(10);
		 */
	}

	public void construireGrille() {

		PointCentral ptC = new PointCentral(0, 0, 0, 0, 0, 0, 10000);
		ArrayList<Point> listePoint = new ArrayList<Point>();
		List<Object> param = new ArrayList<Object>();

		listePoint.add(new Point(-400, 0, 0, ptC));
		listePoint.add(new Point(400, 0, 0, ptC));
		param.add(context);
		param.add(TypeForme.LIGNE.toString());
		param.add(listePoint);
		param.add("rgba(255,255,0,0.8)");
		param.add(ptC);
		forme.creer(param);

		ptC = new PointCentral(0, 0, 0, 0, 0, 0, 10000);
		listePoint = new ArrayList<Point>();
		param = new ArrayList<Object>();
		listePoint.add(new Point(0, -300, 0, ptC));
		listePoint.add(new Point(0, 300, 0, ptC));
		param.add(context);
		param.add(TypeForme.LIGNE.toString());
		param.add(listePoint);
		param.add("rgba(255,25,0,0.8)");
		param.add(ptC);
		forme.creer(param);

	}

	public String getPoint(){		
		return forme.getPoint().toString();
	}
	
	
	public void ajouterPoint(String type,String rayon, String couleur , double x , double y , double z) {

		ptC = new PointCentral(ptC.getXA(),ptC.getYA(),ptC.getZA(),ptC.getDegreX(),ptC.getDegreY(),ptC.getDegreZ() , ptC.getFocal());
		
		List<Object> param = new ArrayList<Object>();
		param.add(context);
		param.add(type);
		param.add(new Point(x, y,z, ptC));
		param.add(rayon);
		param.add(couleur);
		param.add(ptC);
		forme.creer(param);	
	

	}
	
	public void ajouterPoint(String type, String xCentral, String yCentral,
			String zCentral, String xAngle, String yAngle, String zAngle,
			String x, String y, String z, String rayon, String couleur, String f) {

		ptC = new PointCentral(Double.parseDouble(xCentral),
				Double.parseDouble(yCentral), Double.parseDouble(zCentral),
				Double.parseDouble(xAngle), Double.parseDouble(yAngle),
				Double.parseDouble(zAngle), Double.parseDouble(f));

		List<Object> param = new ArrayList<Object>();
		param.add(context);
		param.add(type);
		param.add(new Point(Double.parseDouble(x), Double.parseDouble(y),
				Double.parseDouble(z), ptC));
		param.add(rayon);
		param.add(couleur);
		param.add(ptC);
		forme.creer(param);	
	

	}

	public void ajouterLigne(String type, String xCentral, String yCentral,
			String zCentral, String xAngle, String yAngle, String zAngle,
			String idPoint1, String idPoint2, String epaisseur, String couleur, String f) {
		
		ptC = new PointCentral(Double.parseDouble(xCentral),
				Double.parseDouble(yCentral), Double.parseDouble(zCentral),
				Double.parseDouble(xAngle), Double.parseDouble(yAngle),
				Double.parseDouble(zAngle), Double.parseDouble(f));

		ArrayList<Point> listePoint = new ArrayList<Point>();
		List<Object> param = new ArrayList<Object>();
		
		Cercle cercle = (Cercle) forme.getObjet(idPoint1); 		
		listePoint.add(cercle.getPt());
		cercle = (Cercle) forme.getObjet(idPoint2); 		
		listePoint.add(cercle.getPt());
		param.add(context);
		param.add(TypeForme.LIGNE.toString());
		param.add(listePoint);
		param.add(couleur);
		param.add(ptC);
		forme.creer(param);


		
	}
	
	public void ajouterStructure(String type, String xCentral, String yCentral,
			String zCentral, String xAngle, String yAngle, String zAngle,
			String idLignes, String epaisseur, String couleur, String f) {
		
		ptC = new PointCentral(Double.parseDouble(xCentral),
				Double.parseDouble(yCentral), Double.parseDouble(zCentral),
				Double.parseDouble(xAngle), Double.parseDouble(yAngle),
				Double.parseDouble(zAngle), Double.parseDouble(f));
		ArrayList<Point> listePoint = new ArrayList<Point>();
		List<Object> param = new ArrayList<Object>();
		String[] listeId= idLignes.split(";");
		ArrayList<Forme> listeForme = null;
		
		for (String id : listeId) {
			
			if(listeForme == null){
				listeForme = new ArrayList<Forme>();
			}
			Ligne ligne = (Ligne) forme.getObjet(id); 		
			
			for (Point pt : ligne.getListePt()) {
				listePoint.add(pt);		
			} 		
			
			listeForme.add(ligne);
		}	

		param.add(context);
		param.add(TypeForme.STRUCTURE.toString());
		param.add(listePoint);
		param.add(couleur);
		param.add(ptC);
		param.add(listeForme);
		forme.creer(param);
	}
	
	public void deplacerForme(String id, String xCentral, String yCentral,
			String zCentral, String xAngle, String yAngle, String zAngle,
			String f) {
		ptC.setValue(Double.parseDouble(xCentral),
				Double.parseDouble(yCentral), Double.parseDouble(zCentral),
				Double.parseDouble(xAngle), Double.parseDouble(yAngle),
				Double.parseDouble(zAngle), Double.parseDouble(f));

		forme.deplacerPointCentral(id, xCentral, yCentral, zCentral, xAngle,
				yAngle, zAngle, f);
		initDessin();
	}

	public void deplacerFormeAll(String xCentral, String yCentral,
			String zCentral, String xAngle, String yAngle, String zAngle,
			String f) {
		ptC.setValue(Double.parseDouble(xCentral),
				Double.parseDouble(yCentral), Double.parseDouble(zCentral),
				Double.parseDouble(xAngle), Double.parseDouble(yAngle),
				Double.parseDouble(zAngle), Double.parseDouble(f));

		forme.deplacerPointCentralAll(xCentral, yCentral, zCentral, xAngle,
				yAngle, zAngle, f);
		initDessin();
	}

	private void initDessin() {
		forme.effacer(canvas);
		forme.dessiner(context);
	}

	public Element getElementById(String id) {
		final Element result = DOM.getElementById(id);
		if (null == result) {
			throw new IllegalArgumentException("element with id " + id
					+ " not found");
		}
		return result;
	}

}
